﻿package net.wangit.view.template;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.wangit.Path;
import net.wangit.framework.config.ProjectSettings;
import net.wangit.util.Checker;
import net.wangit.util.FileUtil;
import net.wangit.util.StringUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


public class TemplateFactory {

	private static final Log log = LogFactory.getLog(Template.class);
	private static Map<String, Template> templates = new HashMap<String, Template>();
	private static final String VARIABLE_PREFIX = "${";
	private static final String VARIABLE_SUFFIX = "}";
	private static final String COMBO_PREFIX = "<c>";
	private static final String COMBO_SUFFIX = "</c>";

	public TemplateFactory() {
	}

	public static void clear() {
		templates.clear();
	}

	public static Template getTemplate(String fileName) {
		Template template;
		if (!ProjectSettings.instance().isReloadTemplate()) {
			template = templates.get(fileName);
			if (template != null) {
				return template;
			}
		}
		String path = new StringBuilder(Path.getTemplatePath())
				.append(fileName).toString();
		try {
			if (!FileUtil.exists(path)) {
				log.error(new StringBuilder("template not found : ").append(
						path).toString());
				throw new TemplateException((new StringBuilder(
						"template not found : ")).append(path).toString());
			}
		} catch (SecurityException e) {
			log.error(new StringBuilder(
					"a security manager denies read access to the file : ")
					.append(path).toString());
			throw new TemplateException(new StringBuilder(
					"a security manager denies read access to the file : ")
					.append(path).toString(), e);
		}
		String content = FileUtil.read(path);
		template = createTemplate(content);
		template.setUnits();
		templates.put(fileName, template);
		if (log.isDebugEnabled()) {
			log.debug((new StringBuilder("load template and put it to cache : "))
					.append(fileName).toString());
		}
		return template;
	}

	private static Template createTemplate(String content) {
		Map<String, Template> combos = new HashMap<String, Template>();
		String combo;
		for (int count = 0; !Checker.isEmpty(combo = StringUtil.find(content,
				TemplateFactory.COMBO_PREFIX, TemplateFactory.COMBO_SUFFIX)); count++) {
			int index = content.indexOf(new StringBuilder(
					TemplateFactory.COMBO_PREFIX).append(combo)
					.append(TemplateFactory.COMBO_SUFFIX).toString());
			content = new StringBuilder(content.substring(0, index))
					.append(TemplateFactory.VARIABLE_PREFIX)
					.append(Integer.toString(count))
					.append(TemplateFactory.VARIABLE_SUFFIX)
					.append(content.substring(index + combo.length()
							+ TemplateFactory.COMBO_PREFIX.length()
							+ TemplateFactory.COMBO_SUFFIX.length()))
					.toString();
			combos.put(Integer.toString(count), createTemplate(combo, null));
		}

		return createTemplate(content, combos);
	}

	private static Template createTemplate(String content,
			Map<String, Template> combos) {
		Template template = new Template();
		List<String> pieces = new ArrayList<String>();
		Map<Integer, Object> mapping = new HashMap<Integer, Object>();
		String attribute;
		for (int count = 0; !Checker.isEmpty(attribute = StringUtil.find(
				content, TemplateFactory.VARIABLE_PREFIX,
				TemplateFactory.VARIABLE_SUFFIX)); count++) {
			int index = content.indexOf(new StringBuilder(
					TemplateFactory.VARIABLE_PREFIX).append(attribute)
					.append(TemplateFactory.VARIABLE_SUFFIX).toString());
			String piece = content.substring(0, index);
			content = content.substring(index + attribute.length()
					+ TemplateFactory.VARIABLE_PREFIX.length()
					+ TemplateFactory.VARIABLE_SUFFIX.length());
			pieces.add(piece);
			if (combos != null && combos.containsKey(attribute))
				mapping.put(new Integer(count), combos.get(attribute));
			else
				mapping.put(new Integer(count), attribute.toLowerCase());
		}

		pieces.add(content);
		template.setPieces(pieces);
		template.setMapping(mapping);
		return template;
	}

}
